﻿using System;
using System.Xml.Linq;
using System.Web.WebPages;
using SilenthinkContract.Domain;
using SilenthinkCommon.Extension;
using System.Collections.Specialized;
using SilenthinkContract.Component;

namespace Web.OnlinePay
{
    public class TenPay : IOnlinePay
    {
        private readonly PaymentPlatform platform;

        public TenPay(PaymentPlatform platform)
        {
            this.platform = platform;
        }

        /// <summary>
        /// 支付请求
        /// </summary>
        /// <returns></returns>
        public string CreatePayUrl(PayTrade trade)
        {
            var param = new NameValueCollection();
            var amount = trade.Amount * 100;
            var gateway = trade.Gateway;
            var version = trade.Version.TimestampToString();

            //reqHandler.setGateUrl("https://gw.tenpay.com/gateway/pay.htm");

            //-----------------------------
            //设置支付参数
            //-----------------------------
            param.Add("total_fee", amount.ToString());
            //用户的公网ip,测试时填写127.0.0.1,只能支持10分以下交易
            param.Add("spbill_create_ip", trade.IpAddress);
            param.Add("return_url", platform.CallbackUrl);
            param.Add("partner", platform.MerchantId);
            param.Add("out_trade_no", trade.Id);
            param.Add("notify_url", platform.NotifyUrl);
            param.Add("attach", version);
            param.Add("body", "测试");
            param.Add("bank_type", gateway);//银行直连编码，默认为“DEFAULT”

            //系统可选参数
            param.Add("sign_type", "MD5");
            param.Add("service_version", "1.0");
            param.Add("input_charset", "UTF-8");
            param.Add("sign_key_index", "1");

            //业务可选参数
            /*
             param.Add("attach", "");
             param.Add("product_fee", "");
             param.Add("transport_fee", "");
             param.Add("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
             param.Add("time_expire", "");
             param.Add("buyer_id", "");
             param.Add("goods_tag", "");
             param.Add("agentid", "");
             param.Add("agent_type", "");
             */
            param.Sort().Add("sign", CreateSign(param));

            //获取带参数的url
            return platform.GatewayUrl + param.ToQueryString(true);

        }

        /// <summary>
        /// 通知处理
        /// </summary>
        /// <param name="nv"></param>
        /// <returns></returns>
        public SkResult<PayResult> NotityHandler(NameValueCollection nv)
        {
            var flag = VerifySign(nv);
            var now = DateTime.Now;
            var result = new SkResult<PayResult>();

            if (flag)
            {
                var param = new NameValueCollection();

                var notifyId = nv["notify_id"]; //通知id

                param.Add("notify_id", notifyId);
                param.Add("partner", platform.MerchantId);
                param.Add("sign", CreateSign(param));

                var url = "https://gw.tenpay.com/gateway/verifynotifyid.xml" + param.ToQueryString(true);

                var res = new NameValueCollection();
                var xe = XElement.Load(url).Descendants();

                foreach (var o in xe)
                {
                    res.Add(o.Name.LocalName, o.Value);
                }

                var no = res["out_trade_no"];
                var amount = res["out_trade_no"];
                var thirdPartyNo = res["thirdPartyNo"];
                var paDateTime = res["out_trade_no"].AsDateTime(now);
                var version = res["attach"].StringToTimestamp();
                var signature = nv["sign"];

                result.Extra = res;
                result.Data = new PayResult(no, amount.AsInt(0)/100M, string.Empty, paDateTime, version, signature);

                if (VerifySign(res) && res["retcode"] == "0" && res["trade_state"] == "0" && res["trade_mode"] == "1")
                {
                    result.Status = true;
                }
                else
                {
                    result.Message = "通知验证签名失败";
                }
            }
            else
            {
                result.Message = "验证签名失败";
            }
            return result;
        }

        /// <summary>
        /// 生成签名
        /// </summary>
        /// <param name="nv">待签名参数</param>
        /// <returns></returns>
        private string CreateSign(NameValueCollection nv)
        {
            nv.Add("key", platform.PrivateKey);
            var plain = nv.ToQueryString();
            var sign = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(plain, "MD5");
            return sign == null ? string.Empty : sign.ToLower();
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="nv">待验证签名参数</param>
        /// <returns></returns>
        public bool VerifySign(NameValueCollection nv)
        {
            var filter = new[] { "sign" };
            var param = nv.Filter(filter).Sort();
            return nv["sign"].ToLower().Equals(CreateSign(param));
        }
    }
}